package net.slowpoison.loveclock.client;

import java.util.Random;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Image;

public class Dot {
	private static int GRAVITY = 8;
	private static Random randgen = new Random();
	private static final int DIA = Ticker.getDia();
	private static final int screenWidth = LoveClock.getScreenWidth();
	private static final int screenHeight = LoveClock.getScreenHeight();
	private static final int MAX_PARACHUTES = 20;

	private Image img;
	private int index;
	private int x, y;
	private int xv, yv;
	private int g;
	private int gfactor;
	private int time;
	private DotType type;
	private Animation animationFunc;
	
	private int deg = 0, ddeg, maxDeg;
	private Image parachute = null;
	private int parachuteIndex;
	
	private interface Animation {
		public boolean animate(Dot d);
	}
	
	private static Animation projectileAnim = new Animation() {
		@Override
		public boolean animate(Dot d) {
			boolean animate = true;
			++d.time;	// pseudo time tracking

			d.x += d.xv;
			d.y += d.yv + d.gfactor;
			d.gfactor += d.g; // gravity factor increases by gravity every time to simulate acceleration

			if (d.x >= (screenWidth) || d.x <= -DIA) {
				animate = false;
			} else if (d.y >= screenHeight - DIA) {
				if (d.time > 200) {	// corner case of prolonged animation
					if (d.y > screenHeight)
						animate = false;
				} else {
					d.yv = -(( (d.gfactor + d.yv) >> 1) + ((d.gfactor + d.yv) >> 2) );
					d.gfactor = 2;
					d.y = screenHeight - DIA;
			
					/*d.yv = -(int)(d.yv + d.gfactor/(1+d.time*.02));
					d.yv -= d.yv >> 3;
					d.gfactor = 2;
					d.y = screenHeight - DIA;*/
				}
			} 
			d.setCoord(d.x, d.y);
			return animate;
		}
	};
	
	
	private static Image[] parachutePool = new Image[MAX_PARACHUTES];
	private static boolean[] parachutesUsed = new boolean[MAX_PARACHUTES];
	
	public static void init() {
		for (int i=0; i < parachutePool.length; ++i) {
			Image pImg = new Image("/parachute.png");
			pImg.setVisible(false);
			pImg.setStyleDependentName("Dot", true);
			pImg.getElement().getStyle().setZIndex(200+i);
			LoveClock.add(pImg);
			parachutePool[i] = pImg;
			parachutesUsed[i] = false;
		}
	}
	
	private Image borrowParachute(int[] pi) {
		for (int i=0; i < parachutePool.length; ++i) {
			if (!parachutesUsed[i]) {
				parachutesUsed[i] = true;
				pi[0] = i;
//				Window.alert("request for parachute at index " + i);
				return parachutePool[i];
			}
		}
		return null;
	}

	protected static void returnParachute(Image p, int pi) {
		parachutesUsed[pi] = false;
		p.getElement().setAttribute("style", "-webkit-transform:none");
		p.getElement().getStyle().setZIndex(200+pi);
		p.setVisible(false);
	}

	
	private static Animation parachuteAnim = new Animation() {
		@Override
		public boolean animate(Dot d) {
			boolean animate = true;
			/*
			if (d.time < 5) {
				animate = projectileAnim.animate(d);
				// remember that projectile animation increments time
				if (!animate) {
					d.parachute.setVisible(false);
					// return the parachute to the pool
					returnParachute(d.parachute, d.parachuteIndex);
					d.parachute = null;
					d.parachuteIndex = -1;
				}
				return animate;
			}*/
			if (d.time++ == 0) {
				// deploy parachute
				d.parachute.setVisible(true);
				d.ddeg = randgen.nextInt(20) - 10;
				d.yv = randgen.nextInt(10) + 2;
				d.maxDeg = randgen.nextInt(90) - 45;
			} 
			
			d.y += d.yv;
			d.deg += d.ddeg;
			d.updateRotation();
			if (d.deg <= -d.maxDeg || d.deg >= d.maxDeg) {
				d.ddeg = -d.ddeg;
			}
			
			if (d.y >= screenHeight + 32) {	// factor in height of parachute
				animate = false;
				// return the parachute to the pool
				returnParachute(d.parachute, d.parachuteIndex);
				d.parachute = null;
				d.parachuteIndex = -1;
			} else {
				d.setCoord(d.x, d.y);
			}
			return animate;
		}
	};

	String[] imgs = new String[] { 
			"/heartg-16x16.png",
			"/heart-day-16x16.png",
			"/heart-hour-16x16.png",
			"/heart-min-16x16.png",
			"/heart-16x16.png",
	};
/*			"//localhost/heart-16x16.png",
			"//localhost/heartg-16x16.png", };*/

	public static enum DotType {
		BG,
		HEART_DAYS,
		HEART_HOUR,
		HEART_MIN,
		HEART_SEC,
	}
	
	public void reset() {
		g = GRAVITY;
		gfactor = 2;
		time = 0;
		animationFunc = null;
		if (type == Dot.DotType.BG) {
			img.getElement().setAttribute("style", "z-index:0");
		} else {
			img.getElement().setAttribute("style", "z-index:100");
		}
		setVisible(false);
		
		xv = randgen.nextInt(200) - 100;
		yv = randgen.nextInt(200) - 100;
	}

	public Dot(DotType type, int index) {
		img = new Image(imgs[type.ordinal()]);
		img.setStyleDependentName("Dot", true);
		setCoord(0, 0);
		this.type = type;
		this.index = index;
		reset();
		
	}

	private void initAnimationFunction() {
		if (type != Dot.DotType.HEART_SEC) { // && yv < 0 && yv > -50) {
			int[] pi = new int[]{ 0 };
			parachute = borrowParachute(pi);
			if (parachute == null) {
				animationFunc =  projectileAnim;
				return;
			}
			parachuteIndex = pi[0];
//			img.getElement().getStyle().setZIndex(200+pi[0]);
//			Window.alert("parachute at index " + pi[0]);
			animationFunc =  parachuteAnim;
		} else {
			animationFunc = projectileAnim;
		}
	}

	public void setVisible(boolean b) {
		img.setVisible(b);
		if (parachute != null)
			parachute.setVisible(false);
	}

	public boolean animate() {
		if (animationFunc != null)
			return animationFunc.animate(this);
		else {
			initAnimationFunction();
			return animationFunc.animate(this);
		}
	}

	public DotType getType() {
		return type;
	}

	public Image getImage() {
		return img;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public void setCoord(int x, int y) {
		this.x = x;
		this.y = y;
		img.getElement().getStyle().setLeft(x, Unit.PX);
		img.getElement().getStyle().setTop(y, Unit.PX);
		if (parachute != null) {
			parachute.getElement().getStyle().setLeft(x - 8, Unit.PX);
			parachute.getElement().getStyle().setTop(y - 32, Unit.PX);
		}
	}
	
	protected void updateRotation() {
		if (parachute != null)
			parachute.getElement().setAttribute("style", 
					"-webkit-transform:rotate(" + deg + "deg);" +
					"-webkit-transform-origin: bottom; z-index: " + (200 + parachuteIndex));
		img.getElement().setAttribute("style", 
					"-webkit-transform:rotate(" + deg + "deg);" +
					"-webkit-transform-origin: top; z-index: " + (200 + parachuteIndex));
	}

	public void set(DotType type, boolean b, int x, int y) {
		this.type = type;
		img.setUrl(imgs[type.ordinal()]);
		setVisible(b);
		setCoord(x, y);
		
		if (type == Dot.DotType.BG) {
			img.getElement().getStyle().setZIndex(0);
		} else {
			img.getElement().getStyle().setZIndex(100);
		}
	}
}